# -*- coding: utf-8 -*-
# Author   : ZhangQing
# Time     : 2025-08-04 23:31
# File     : project_routes.py
# Project  : codebuddy_craft
# Desc     : 项目管理接口

# backend/api/project_routes.py
"""
项目API路由 📁

处理项目CRUD、协作管理等功能
"""

from fastapi import APIRouter, Depends, HTTPException, status, Query
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, or_, and_
from sqlalchemy.orm import selectinload
from typing import List, Optional

from backend.database.connection import get_db
from backend.models.user import User
from backend.models.project import Project, ProjectCollaborator, ProjectTemplate, ProjectStatus, ProjectVisibility, \
    CollaboratorRole
from backend.models.file import File
from backend.api.auth_routes import require_auth
from backend.utils.logger import get_logger
from backend.utils.log_utils import log_business_event
from backend.schemas.project import (
    ProjectResponse, ProjectCreateRequest, ProjectUpdateRequest,
    ProjectListResponse, CollaboratorResponse, CollaboratorAddRequest
)

router = APIRouter()
logger = get_logger(__name__)


async def check_project_access(
        project_id: str,
        user: User,
        db: AsyncSession,
        required_role: CollaboratorRole = CollaboratorRole.VIEWER
) -> Project:
    """检查项目访问权限"""

    # 获取项目信息
    result = await db.execute(
        select(Project)
        .options(selectinload(Project.collaborators))
        .where(Project.id == project_id)
    )
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="项目不存在"
        )

    # 检查访问权限
    if project.owner_id == user.id:
        return project  # 项目所有者拥有全部权限

    # 检查协作者权限
    collaborator = None
    for collab in project.collaborators:
        if collab.user_id == user.id:
            collaborator = collab
            break

    if not collaborator:
        if project.visibility == ProjectVisibility.PUBLIC:
            # 公开项目，非协作者只有查看权限
            if required_role != CollaboratorRole.VIEWER:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail="没有权限执行此操作"
                )
        else:
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="没有权限访问此项目"
            )
    else:
        # 检查协作者角色权限
        role_hierarchy = {
            CollaboratorRole.VIEWER: 1,
            CollaboratorRole.DEVELOPER: 2,
            CollaboratorRole.ADMIN: 3,
            CollaboratorRole.OWNER: 4
        }

        if role_hierarchy.get(collaborator.role, 0) < role_hierarchy.get(required_role, 0):
            raise HTTPException(
                status_code=status.HTTP_403_FORBIDDEN,
                detail="权限不足"
            )

    return project


@router.post("/", response_model=ProjectResponse)
async def create_project(
        project_data: ProjectCreateRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """创建新项目 ✨"""

    # 检查项目名称是否重复（同一用户下）
    result = await db.execute(
        select(Project).where(
            Project.name == project_data.name,
            Project.owner_id == current_user.id,
            Project.status != ProjectStatus.DELETED
        )
    )
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="项目名称已存在"
        )

    # 创建项目
    new_project = Project(
        name=project_data.name,
        description=project_data.description,
        tech_stack=project_data.tech_stack or [],
        visibility=project_data.visibility or ProjectVisibility.PRIVATE,
        settings=project_data.settings or {},
        tags=project_data.tags or [],
        owner_id=current_user.id
    )

    db.add(new_project)
    await db.commit()
    await db.refresh(new_project)

    # 如果使用模板，创建模板文件
    if project_data.template_id:
        await _create_files_from_template(new_project.id, project_data.template_id, db)

    logger.success(f"项目创建成功: {new_project.name} by {current_user.username}")
    log_business_event("PROJECT_CREATED", user_id=current_user.id, project_id=new_project.id)

    return ProjectResponse.from_orm(new_project)


@router.get("/", response_model=ProjectListResponse)
async def get_user_projects(
        skip: int = Query(0, ge=0, description="跳过数量"),
        limit: int = Query(20, le=100, description="返回数量"),
        status_filter: Optional[ProjectStatus] = Query(None, description="状态过滤"),
        search: Optional[str] = Query(None, description="搜索关键词"),
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取用户项目列表 📋"""

    # 构建查询条件
    filters = [
        or_(
            Project.owner_id == current_user.id,
            Project.collaborators.any(ProjectCollaborator.user_id == current_user.id)
        )
    ]

    if status_filter:
        filters.append(Project.status == status_filter)
    else:
        filters.append(Project.status != ProjectStatus.DELETED)

    if search:
        filters.append(
            or_(
                Project.name.ilike(f"%{search}%"),
                Project.description.ilike(f"%{search}%")
            )
        )

    # 查询项目总数
    count_query = select(func.count(Project.id)).where(and_(*filters))
    total_result = await db.execute(count_query)
    total = total_result.scalar()

    # 查询项目列表
    query = (
        select(Project)
        .options(selectinload(Project.owner))
        .where(and_(*filters))
        .order_by(Project.updated_at.desc())
        .offset(skip)
        .limit(limit)
    )

    result = await db.execute(query)
    projects = result.scalars().all()

    return ProjectListResponse(
        items=[ProjectResponse.from_orm(project) for project in projects],
        total=total,
        skip=skip,
        limit=limit
    )


@router.get("/{project_id}", response_model=ProjectResponse)
async def get_project(
        project_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取项目详情 📖"""

    project = await check_project_access(project_id, current_user, db)

    # 更新最后访问时间
    from sqlalchemy import func
    project.last_accessed_at = func.now()
    await db.commit()

    return ProjectResponse.from_orm(project)


@router.put("/{project_id}", response_model=ProjectResponse)
async def update_project(
        project_id: str,
        project_update: ProjectUpdateRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """更新项目信息 ✏️"""

    project = await check_project_access(
        project_id, current_user, db, CollaboratorRole.ADMIN
    )

    # 检查项目名称是否重复
    if project_update.name and project_update.name != project.name:
        result = await db.execute(
            select(Project).where(
                Project.name == project_update.name,
                Project.owner_id == project.owner_id,
                Project.id != project_id,
                Project.status != ProjectStatus.DELETED
            )
        )
        if result.scalar_one_or_none():
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="项目名称已存在"
            )

    # 更新项目信息
    update_data = project_update.dict(exclude_unset=True)
    for field, value in update_data.items():
        setattr(project, field, value)

    await db.commit()
    await db.refresh(project)

    logger.success(f"项目更新成功: {project.name}")
    log_business_event("PROJECT_UPDATED", user_id=current_user.id, project_id=project.id)

    return ProjectResponse.from_orm(project)


@router.delete("/{project_id}")
async def delete_project(
        project_id: str,
        permanent: bool = Query(False, description="是否永久删除"),
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """删除项目 🗑️"""

    # 只有项目所有者可以删除项目
    result = await db.execute(
        select(Project).where(
            Project.id == project_id,
            Project.owner_id == current_user.id
        )
    )
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="项目不存在或没有删除权限"
        )

    if permanent:
        # 永久删除
        await db.delete(project)
        log_business_event("PROJECT_PERMANENTLY_DELETED", user_id=current_user.id, project_id=project_id)
        message = "项目已永久删除"
    else:
        # 软删除
        project.status = ProjectStatus.DELETED
        log_business_event("PROJECT_DELETED", user_id=current_user.id, project_id=project_id)
        message = "项目已删除"

    await db.commit()

    logger.warning(f"项目删除: {project.name} by {current_user.username}")

    return {"message": message}


@router.post("/{project_id}/restore")
async def restore_project(
        project_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """恢复已删除的项目 🔄"""

    result = await db.execute(
        select(Project).where(
            Project.id == project_id,
            Project.owner_id == current_user.id,
            Project.status == ProjectStatus.DELETED
        )
    )
    project = result.scalar_one_or_none()

    if not project:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="项目不存在或无法恢复"
        )

    project.status = ProjectStatus.ACTIVE
    await db.commit()

    logger.success(f"项目恢复成功: {project.name}")
    log_business_event("PROJECT_RESTORED", user_id=current_user.id, project_id=project_id)

    return {"message": "项目已恢复"}


@router.get("/{project_id}/collaborators", response_model=List[CollaboratorResponse])
async def get_project_collaborators(
        project_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取项目协作者列表 👥"""

    await check_project_access(project_id, current_user, db)

    result = await db.execute(
        select(ProjectCollaborator)
        .options(selectinload(ProjectCollaborator.user))
        .where(ProjectCollaborator.project_id == project_id)
    )
    collaborators = result.scalars().all()

    return [CollaboratorResponse.from_orm(collab) for collab in collaborators]


@router.post("/{project_id}/collaborators")
async def add_collaborator(
        project_id: str,
        collaborator_data: CollaboratorAddRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """添加项目协作者 ➕"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.ADMIN)

    # 查找要添加的用户
    result = await db.execute(
        select(User).where(
            or_(
                User.username == collaborator_data.username_or_email,
                User.email == collaborator_data.username_or_email
            )
        )
    )
    target_user = result.scalar_one_or_none()

    if not target_user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="用户不存在"
        )

    # 检查是否已是协作者
    result = await db.execute(
        select(ProjectCollaborator).where(
            ProjectCollaborator.project_id == project_id,
            ProjectCollaborator.user_id == target_user.id
        )
    )
    existing_collab = result.scalar_one_or_none()

    if existing_collab:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="用户已是项目协作者"
        )

    # 添加协作者
    new_collaborator = ProjectCollaborator(
        project_id=project_id,
        user_id=target_user.id,
        role=collaborator_data.role,
        permissions=collaborator_data.permissions or {}
    )

    db.add(new_collaborator)
    await db.commit()
    await db.refresh(new_collaborator)

    logger.success(f"协作者添加成功: {target_user.username} -> {project_id}")
    log_business_event("COLLABORATOR_ADDED", user_id=current_user.id, project_id=project_id,
                       details={"collaborator_id": target_user.id, "role": collaborator_data.role.value})

    return {"message": "协作者添加成功"}


@router.delete("/{project_id}/collaborators/{user_id}")
async def remove_collaborator(
        project_id: str,
        user_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """移除项目协作者 ➖"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.ADMIN)

    result = await db.execute(
        select(ProjectCollaborator).where(
            ProjectCollaborator.project_id == project_id,
            ProjectCollaborator.user_id == user_id
        )
    )
    collaborator = result.scalar_one_or_none()

    if not collaborator:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="协作者不存在"
        )

    await db.delete(collaborator)
    await db.commit()

    logger.success(f"协作者移除成功: {user_id} from {project_id}")
    log_business_event("COLLABORATOR_REMOVED", user_id=current_user.id, project_id=project_id,
                       details={"collaborator_id": user_id})

    return {"message": "协作者移除成功"}


@router.get("/{project_id}/stats")
async def get_project_stats(
        project_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取项目统计信息 📊"""

    project = await check_project_access(project_id, current_user, db)

    # 文件统计
    file_stats_result = await db.execute(
        select(
            func.count(File.id).label('file_count'),
            func.sum(File.lines).label('total_lines'),
            func.sum(File.size).label('total_size')
        ).where(File.project_id == project_id)
    )
    file_stats = file_stats_result.first()

    # 文件类型统计
    file_type_result = await db.execute(
        select(
            File.file_type,
            func.count(File.id).label('count')
        )
        .where(File.project_id == project_id)
        .group_by(File.file_type)
    )
    file_types = {row.file_type: row.count for row in file_type_result}

    # 协作者统计
    collaborator_count_result = await db.execute(
        select(func.count(ProjectCollaborator.id))
        .where(ProjectCollaborator.project_id == project_id)
    )
    collaborator_count = collaborator_count_result.scalar()

    return {
        "project_id": project_id,
        "file_count": file_stats.file_count or 0,
        "total_lines": file_stats.total_lines or 0,
        "total_size": file_stats.total_size or 0,
        "file_types": file_types,
        "collaborator_count": collaborator_count,
        "created_at": project.created_at.isoformat() if project.created_at else None,
        "last_updated": project.updated_at.isoformat() if project.updated_at else None
    }


async def _create_files_from_template(project_id: str, template_id: str, db: AsyncSession):
    """从模板创建文件"""
    result = await db.execute(
        select(ProjectTemplate).where(ProjectTemplate.id == template_id)
    )
    template = result.scalar_one_or_none()

    if not template:
        return

    # 创建模板文件
    for file_path, content in template.template_files.items():
        file_name = file_path.split('/')[-1]
        new_file = File(
            name=file_name,
            path=file_path,
            content=content,
            project_id=project_id,
            file_type=file_name.split('.')[-1] if '.' in file_name else 'txt'
        )
        db.add(new_file)

    # 更新模板使用次数
    template.usage_count += 1
    await db.commit()


